home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / console / svgatext.3 / svgatext / SVGATextMode-1.3 / modedata.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-06  |  14.1 KB  |  437 lines

  1. /*  SVGATextMode -- An SVGA textmode manipulation/enhancement tool
  2.  *
  3.  *  Copyright (C) 1995,1996  Koen Gadeyne
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20.  
  21. /***
  22.  *** modedata: routines for text/graphics mode grabbing
  23.  ***/
  24.  
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28.  
  29. #ifndef DOS
  30. #include <unistd.h>
  31. #include <asm/io.h>
  32. #endif
  33.  
  34. #include "misc.h"
  35. #include "vga_prg.h"
  36. #include "messages.h"
  37. #include "probe.h"
  38. #include "modedata.h"
  39.  
  40. #ifdef DOS
  41. #define get_VGA_io_perm(x)
  42. #undef Renounce_SUID
  43. #define Renounce_SUID
  44. extern int optind;
  45. #endif
  46.  
  47.  
  48. int roundup2(int num)
  49.  /* round num up to the nearest power of 2 */
  50. {
  51.   int cnt=0;
  52.   while (num)
  53.   {
  54.     num >>=1;
  55.     cnt++;
  56.   }
  57.   return(1<<cnt);
  58. }
  59.  
  60. bool check2(int *low, int *high, bool *wrap)
  61. {
  62.   if (*high < *low)
  63.     {
  64.       *high += roundup2(*low - *high -1);
  65.       *wrap = TRUE;
  66.       return TRUE;
  67.     }
  68.     return FALSE;
  69. }
  70.  
  71. int wrapcheck(int *active , int *start_sync, int *stop_sync, int *total,
  72.               int *start_blank, int *end_blank,
  73.               int badsyncmask, int wrapmsgmask)
  74. /* check for wrapping at standard VGA register limits: e.g. 1025 --> 1 */
  75. {
  76.   bool wrap = FALSE;
  77.   int mask = 0;
  78.  
  79.   check2(active, start_sync, &wrap);
  80.   check2(start_sync, stop_sync, &wrap);
  81.   check2(start_blank, end_blank, &wrap);
  82.      
  83.   if (*total < *stop_sync)
  84.     {
  85.       if (!check2(start_sync, total, &wrap)) mask |= badsyncmask;
  86.     }
  87.     
  88.   if (wrap) mask |= wrapmsgmask;
  89.  
  90.   return(mask);
  91. }
  92.  
  93. int wrapcheck_preset(int *active , int *start_sync, int *stop_sync, int *total,
  94.                      int *start_blank, int *end_blank,
  95.                      int wrapmsgmask, int realval)
  96. /* check for more severe/undetected wrapping with given (=known) size */
  97. {
  98.   int offset = 0;
  99.   
  100.   if (realval == *active) return 0;
  101.   if ((realval % 1024) == *active)
  102.   {
  103.     offset = realval - *active;
  104.     *active += offset;
  105.     *start_sync += offset;
  106.     *stop_sync += offset;
  107.     *total += offset;
  108.     return wrapmsgmask;
  109.   }
  110.   else
  111.     /* the preset value doesn't match with measured result. Wait till post_clockprobe_intelligence
  112.      * before storing an error: it could be a special mode
  113.      */
  114.     return 0;
  115. }
  116.  
  117. #define mul_Vtim(val) do {\
  118.     m->mode_line.VDisplay *= (val);\
  119.     m->mode_line.VSyncStart *= (val);\
  120.     m->mode_line.VSyncEnd *= (val);\
  121.     m->mode_line.VTotal *= (val);\
  122.     m->startvbl *= (val);\
  123.     m->endvbl *= (val);\
  124.     } while (0)
  125.  
  126. #define div_Vtim(val) do {\
  127.     m->mode_line.VDisplay /= (val);\
  128.     m->mode_line.VSyncStart /= (val);\
  129.     m->mode_line.VSyncEnd /= (val);\
  130.     m->mode_line.VTotal /= (val);\
  131.     m->startvbl /= (val);\
  132.     m->endvbl /= (val);\
  133.     } while (0)
  134.  
  135.  
  136. void pre_clockprobe_intelligence(modestruct* m, int xx, int yy)
  137. {
  138.  /* check for "wraparound" of the H and V values: this can be caused by some chipsets using 
  139.   * their own, extended custom registers for setting H/V parameters.
  140.   * A common example of this is the following V-parameters: 1024 5 7 25 instead of
  141.   * 1024 1029 1031 1049
  142.   */
  143.   
  144.   m->remarks |= wrapcheck(&m->mode_line.VDisplay, &m->mode_line.VSyncStart,
  145.                           &m->mode_line.VSyncEnd, &m->mode_line.VTotal,
  146.                           &m->startvbl, &m->endvbl, 
  147.                           MSG_BAD_VSYNC_STOP, MSG_VTIM_MOD);
  148.   
  149.   /* see if vert. resolution was multiplied by 2 (normally for modes with >1024 lines) */
  150.  
  151.   if (GMOFLG_ISSET(*m,VERT_DOUBLE)) mul_Vtim(2);
  152.  
  153.   /* now check that really big modes didn't cause a giant wrap that can't be detected by the code above.
  154.    * This could occur e.g. in 1600x12000 modes, which would detect as only 176 (1200-1024) pixels.
  155.    */
  156.  
  157.   if (yy>0)
  158.   {
  159.     m->remarks |= wrapcheck_preset(&m->mode_line.VDisplay, &m->mode_line.VSyncStart,
  160.                                    &m->mode_line.VSyncEnd, &m->mode_line.VTotal,
  161.                                    &m->startvbl, &m->endvbl, 
  162.                                    MSG_PRESET_VTIM_MOD, yy);
  163.   }
  164.  
  165.   /* same story for hor. timings */
  166.   
  167.   m->remarks |= wrapcheck(&m->mode_line.HDisplay, &m->mode_line.HSyncStart,
  168.                           &m->mode_line.HSyncEnd, &m->mode_line.HTotal,
  169.                           &m->starthbl, &m->endhbl, 
  170.                           MSG_BAD_HSYNC_STOP, MSG_HTIM_MOD);  
  171.   if (xx>0)
  172.   {
  173.     m->remarks |= wrapcheck_preset(&m->mode_line.HDisplay, &m->mode_line.HSyncStart,
  174.                                    &m->mode_line.HSyncEnd, &m->mode_line.HTotal,
  175.                                    &m->starthbl, &m->endhbl, 
  176.                                    MSG_PRESET_HTIM_MOD, xx);  
  177.   }
  178.   
  179.   /* V-timings could still be wrapped. If so, this will produce extreme X/Y ratios
  180.    * e.g. 1280/2 instead of 1280/1026. This can be arranged by adding 1024 to all V-timings
  181.    * until the ratio is "reasonable"
  182.    */
  183.   
  184.   while ( ((float)m->mode_line.HDisplay / (float)m->mode_line.VDisplay) > 10.0 )
  185.   {
  186.     m->mode_line.VDisplay += 1024;
  187.     m->mode_line.VSyncStart += 1024;
  188.     m->mode_line.VSyncEnd += 1024;
  189.     m->mode_line.VTotal += 1024;
  190.     m->remarks |= MSG_Y_WRAP_COMPENSATE;
  191.   }
  192.  
  193. /*  
  194.   PDEBUG(("Pre-Clockprobe: %d %d %d %d  %d %d %d %d\n",\
  195.            m->mode_line.HDisplay, m->mode_line.HSyncStart, m->mode_line.HSyncEnd, m->mode_line.HTotal,\
  196.            m->mode_line.VDisplay, m->mode_line.VSyncStart, m->mode_line.VSyncEnd, m->mode_line.VTotal));
  197. */
  198. }
  199.  
  200. #define div_Htim(val) do {\
  201.     m->mode_line.HDisplay /= (val);\
  202.     m->mode_line.HSyncStart /= (val);\
  203.     m->mode_line.HSyncEnd /= (val);\
  204.     m->mode_line.HTotal /= (val);\
  205.     m->starthbl /= (val);\
  206.     m->endhbl /= (val);\
  207.     m->mode_line.pixelClock /= (val);\
  208.     } while (0);
  209.  
  210. #define mul_Htim(val) do {\
  211.     m->mode_line.HDisplay *= (val);\
  212.     m->mode_line.HSyncStart *= (val);\
  213.     m->mode_line.HSyncEnd *= (val);\
  214.     m->mode_line.HTotal *= (val);\
  215.     m->starthbl *= (val);\
  216.     m->endhbl *= (val);\
  217.     m->mode_line.pixelClock *= (val);\
  218.     } while (0);
  219.  
  220.  
  221. void post_clockprobe_intelligence(modestruct* m, int xx, int yy)
  222. {
  223.   float ratio;
  224.   int ratiodiv;
  225.   
  226.   /* take double scanning into account. Must be done AFTER clock probe,
  227.    * because it must not be influenced by this.
  228.    * Multiscan not done in text mode, since there the font size _is_ the font size.
  229.    */
  230.   if (GMOFLG_ISSET(*m,(MULTISCAN|DOUBLESCAN|VERT_DOUBLE)))
  231.   {
  232.     /* standard doublescan */
  233.     int div = ( GMOFLG_ISSET(*m,DOUBLESCAN) ? 2 : 1 );
  234.     /* doublescan using font height */
  235.     if (m->txt_gr_mode==MODE_GRAPHICS) div *=  m->mode_line.FontHeight;
  236.     div_Vtim(div);
  237.   }
  238.  
  239.   /* calculate X/Y ratio */
  240.   
  241.   ratio = (float)m->mode_line.HDisplay / (float)m->mode_line.VDisplay;
  242.   ratiodiv = (int) ((ratio / GOLDEN_RATIO) + 0.5);
  243.   
  244.          /* using a "ratiomul" here could reveal pixmux modes on some cards */
  245.  
  246.   PDEBUG(("Original X/Y ratio = %1.2f ; ratio divisor = %d\n\n", ratio, ratiodiv));
  247.  
  248.   /* first see if the pre-set X/Y sizes can help us resolve some problems before we start guessing */
  249.  
  250.   if (xx>0)
  251.   {
  252.     int xratio;
  253.     /* 15/16/24/32 bit modes could cause double/triple/quad H-size */
  254.     xratio = (m->mode_line.HDisplay*100) / xx; /* multiply with 100 allows integer arithmetic */
  255.     switch (xratio)
  256.     {
  257.        case 99:
  258.        case 100:
  259.        case 101: break; /* 1:1 ratio: mode was probed OK. */
  260.  
  261.        case 199:
  262.        case 200:
  263.        case 201: div_Htim(2);
  264.                  if ((GMOFLG_ISSET(*m,PCS_DIV2)) && (GMOFLG_ISSET(*m,SHIFT_CGA256C)) && (GMOFLG_ISSET(*m,(DOUBLESCAN|MULTISCAN))) && (ratiodiv==2))
  265.                    m->remarks |= MSG_CGA;
  266.                  else
  267.                    m->remarks |= MSG_16BPP;
  268.                  ratiodiv /= 2;
  269.                  break; 
  270.  
  271.        case 299:
  272.        case 300:
  273.        case 301: div_Htim(3);
  274.                  m->remarks |= MSG_24BPP;
  275.                  ratiodiv /= 3;
  276.                  break; 
  277.  
  278.        case 399:
  279.        case 400:
  280.        case 401: div_Htim(4);
  281.                  m->remarks |= MSG_32BPP;
  282.                  ratiodiv /= 4;
  283.                  break; 
  284.  
  285.       /* should we provide the ranges 49-51 etc? for pixmux modes? */
  286.       default: m->remarks |= MSG_PRESET_X_WRONG;
  287.     }
  288.   }
  289.   
  290.   if (yy>0)
  291.   {
  292.     int yratio;
  293.     /* interlaced modes could cause halved V-size */
  294.     yratio = (m->mode_line.VDisplay*100) / yy; /* multiply with 100 allows integer arithmetic */
  295.     switch (yratio)
  296.     {
  297.        case 99:
  298.        case 100:
  299.        case 101: break; /* 1:1 ratio: mode was probed OK. */
  300.  
  301.        case 49:
  302.        case 50:
  303.        case 51: mul_Vtim(2);
  304.                 GMOFLG_SET(*m,INTERLACE);
  305.                 m->remarks |= MSG_IS_INTERLACE;
  306.                 ratiodiv /= 2;
  307.                 break; 
  308.  
  309.       default: m->remarks |= MSG_PRESET_Y_WRONG;
  310.     }
  311.   }
  312.  
  313.   /* Could this mode be interlaced ?
  314.    * Trigger on some common V-sizes.
  315.    * This will work only on those particular sizes of course.
  316.    * This code only works for those cards that divide V-timings by 2 for interlacing (i.e. almost all cards)
  317.    */
  318.  
  319.   if ( (m->txt_gr_mode == MODE_GRAPHICS) && (ratiodiv > 1) )
  320.   {
  321.     if (yy<=0) switch (m->mode_line.VDisplay) /* only when Y-size is not pre-set */
  322.     {
  323.       case 480/2:    /* 640x480 */
  324.       case 600/2:    /* 800x600 */
  325.       case 768/2:    /* 1024x768 */ 
  326.       case 900/2:    /* 1152x900 */
  327.       case 910/2:    /* 1152x910 */
  328.       case 1024/2:    /* 1280x1024 */
  329.       case 1200/2:    /* 1600x1200 */
  330.           if ((ratiodiv % 2) == 0)   /* ratio = 2, 4, ... */
  331.           {
  332.             mul_Vtim(2);
  333.             m->remarks |= MSG_INTERLACE;
  334.             GMOFLG_SET(*m,INTERLACE);
  335.             ratiodiv /=2;
  336.           }
  337.       default:
  338.           break;
  339.     }
  340.  
  341.    /* after interlacing has been accounted for, check for more trouble */
  342.     
  343.    /* detect 320x200 -like 256 color modes: when this flag is set, the VGA chip outputs data only every 2
  344.     * pixel clocks by assembling two consecutive (4-bit) "pixels" into one (8-bit) pixel. These are the so-called
  345.     * "packed pixel" modes (is this true?).
  346.     * some modes don't have this bit set, and are STILL 320x200. they will need another detection mechanism.
  347.     *
  348.     * There's a problem with this: many VGA cards have an extended register that overrides this setting, so 
  349.     * that, even when the PCS_DIV2 bit is set, the card is STILL working at its full speed, and not the CGA
  350.     * emulation mode. S3 for example has CRTC reg 0x32, where bit 4 enables 256 color modes. Setting the
  351.     * PCS_DIV2 bit doesn't have any effect anymore. Worse even: XFree86 for some odd reason sets the PCS_DIV2
  352.     * flag, although this bit doesn't do what it should do at that moment (XFree86 uses the S3 "256 color
  353.     * enhanced mode" bit just mentionned instead). So that would cause a 640x480 mode on S3 to be detected as 
  354.     * 320x480, since the PCS_DIV2 bit was set (but non-functional). *Sigh*.
  355.     *
  356.     * If you want to remain device-independent, then you're the sucker, since then the PCS_DIV2 is not a certain
  357.     * indication for half-speed 256 color modes anymore...
  358.     */
  359.  
  360.     if (xx<=0) /* only when X-size was not given */
  361.     {
  362.       if (ratiodiv == 2)
  363.       {
  364.         div_Htim(2); ratiodiv /= 2;
  365.         if ( (GMOFLG_ISSET(*m,PCS_DIV2)) && (GMOFLG_ISSET(*m,SHIFT_CGA256C)) && (GMOFLG_ISSET(*m,(DOUBLESCAN|MULTISCAN))) )
  366.           m->remarks |= MSG_GOLDENRATIO_X_CGA;
  367.         else
  368.           m->remarks |= MSG_GOLDENRATIO_X_HICOLOR;
  369.       }
  370.     }
  371.     if (ratiodiv > 1) m->remarks |= MSG_WEIRD;
  372.   }
  373. }
  374.  
  375.  
  376. void getmode(modestruct* m, bool probe_clock, bool raw_mode, int initial_x, int initial_y)
  377.  
  378. /* get mode parameters. When initial_x and/or initial_y are specified, less guessing is done */
  379.  
  380. {
  381.   m->remarks=0;
  382.  
  383.   get_VGA_io_perm(CS_VGA);
  384.   unlock(CS_VGA); /* unlock standard VGA locked registers */
  385.  
  386.   m->mode_line.HDisplay = Get_HOR_DISPL_END()*8;
  387.   m->mode_line.HSyncStart = Get_HSYNC_START()*8;
  388.   m->mode_line.HSyncEnd = Get_HSYNC_END()*8;
  389.   m->mode_line.HTotal = Get_HOR_TOTAL()*8;
  390.   m->mode_line.VDisplay = Get_VERT_DISPL_END();
  391.   m->mode_line.VSyncStart = Get_VRETRACE_START();
  392.   m->mode_line.VSyncEnd = Get_VRETRACE_END();
  393.   m->mode_line.VTotal = Get_VERT_TOTAL();
  394.      
  395.   m->mode_line.FontWidth = get_charwidth();
  396.   m->mode_line.FontHeight = Get_MAX_SCANLINE();
  397.      
  398.   m->mode_line.hpol = Get_HSYNC_POLARITY();
  399.   m->mode_line.vpol = Get_VSYNC_POLARITY();
  400.      
  401.   m->starthbl = Get_HBLANK_START()*8;
  402.   m->endhbl = Get_HBLANK_END()*8;
  403.   m->startvbl = Get_VBLANK_START();
  404.   m->endvbl = Get_VBLANK_END();
  405.  
  406.   m->txt_gr_mode = Get_TX_GR_Mode();
  407.  
  408.   /* special mode flags */
  409.   m->mode_flags = 0;
  410.   if (Inb_CRTC(0x09) & 0x80) GMOFLG_SET(*m,DOUBLESCAN);
  411.   /* MSL=2 is also used for doublescanning in graphics mode */
  412.   if ((m->txt_gr_mode==MODE_GRAPHICS) && (m->mode_line.FontHeight>1)) GMOFLG_SET(*m,MULTISCAN);
  413.   if (Inb_SEQ(0x01) & 0x08) GMOFLG_SET(*m,CLOCKDIV2);  /* this has already been taken into account by clock probe */
  414.   if (Inb_CRTC(0x17) & 0x40) GMOFLG_SET(*m,BYTEMODE); else GMOFLG_SET(*m,WORDMODE);
  415.   if (Inb_CRTC(0x14) & 0x40) GMOFLG_SET(*m,DOUBLEWORDMODE);
  416.   if (Inb_CRTC(0x17) & 0x04) GMOFLG_SET(*m,VERT_DOUBLE);
  417.   if (inb_ATR_CTL(0x10) & 0x40) GMOFLG_SET(*m,PCS_DIV2);
  418.   if (Inb_CRTC(0x17) & 0x08) GMOFLG_SET(*m,CNT_BY_2);
  419.   if (Inb_GR_CTL(0x05) & 0x20) GMOFLG_SET(*m,SHIFT_CGA4C);
  420.   if (Inb_GR_CTL(0x05) & 0x40) GMOFLG_SET(*m,SHIFT_CGA256C);
  421.   PDEBUG(("Mode flags (mask) = 0x%08x\n", m->mode_flags));
  422.   
  423.   m->logical_width = Inb_CRTC(0x13)*8;
  424.   if (GMOFLG_ISSET(*m,DOUBLEWORDMODE)) m->logical_width *=8;
  425.   else if (GMOFLG_ISSET(*m,WORDMODE)) m->logical_width *=4;
  426.   else m->logical_width *=2;
  427.  
  428.   /* the "smart" code. This is where the mistakes will be made... */
  429.   if (!raw_mode) pre_clockprobe_intelligence(m, initial_x, initial_y);
  430.   
  431.   if (probe_clock) measure_pixclock(m);
  432.  
  433.   /* this part of the smart stuff must be AFTER the clock probing, because it would cause wrong results */
  434.   if (!raw_mode) post_clockprobe_intelligence(m, initial_x, initial_y);
  435.  
  436. }
  437.